﻿using System;
using System.Text;
using System.Collections.Generic;
using SysLE = System.Linq.Expressions;

namespace Bouyei.SqlProvider.Extensions
{
    using Expression;
    using Structure;

    public static class SqlExtension
    {
        #region From关键字拼接
        public static From From(this Select select, params string[] tableName)
        {
            From from = new From(tableName);
            from.SqlString = select.SqlString + from.ToString();

            return from;
        }

        public static From<T> From<T>(this Select<T> select) where T : class
        {
            From<T> from = new From<T>();
            from.SqlString = select.SqlString + from.ToString();

            return from;
        }

        public static From From(this Delete delete,string tableName)
        {
            From from = new Expression.From(tableName);
            from.SqlString = delete.ToString() + from.ToString();

            return from;
        }

        public static From<T> From<T>(this Delete<T> delete) where T:class
        {
            From<T> from = new Expression.From<T>();
            from.SqlString = delete.ToString() + from.ToString();

            return from;
        }
        #endregion

        #region where关键字拼接
        /// <summary>
        /// 与条件
        /// </summary>
        /// <param name="from"></param>
        /// <param name="values"></param>
        /// <returns></returns>
        public static Where Where(this From from, params KeyValue[] values)
        {
            Where where = new Where(values);
            where.SqlString = from.SqlString + where.ToString();

            return where;
        }

        /// <summary>
        /// 自定义条件
        /// </summary>
        /// <param name="from"></param>
        /// <param name="andOrs"></param>
        /// <param name="values"></param>
        /// <returns></returns>
        public static Where Where(this From from, AndOr[] andOrs, params KeyValue[] values)
        {
            Where where = new Where(values);
            where.SqlString = from.SqlString + where.ToString(andOrs);

            return where;
        }

        public static Where Where(this From from, string whereStr)
        {
            Where where = new Where(whereStr);
            return where;
        }

        public static Where<T> Where<T>(this From<T> from, T value) where T : class
        {
            Where<T> where = new Where<T>(value);
            where.SqlString = from.SqlString + where.ToString();

            return where;
        }

        public static Where<T> Where<T>(this From<T> from, SysLE.Expression<Func<T, bool>> expression) where T : class
        {
            Where<T> where = new Where<T>(default(T));
            where.SqlString = from.SqlString + where.ToString() + SysExpression_Analyize(expression);

            return where;
        }

        public static Where Where(this Set set,string wherestr)
        {
            Where where = new Expression.Where(wherestr);
            where.SqlString = set.SqlString + where.ToString();

            return where;
        }

        public static Where<T> Where<T>(this Set<T> set,T value)
        {
            Where<T> where = new Expression.Where<T>(value);
            where.SqlString = set.SqlString + where.ToString();

            return where;
        }

        private static string SysExpression_Analyize<T>(SysLE.Expression<Func<T, bool>> exp)
        {
            StringBuilder builder = new StringBuilder();
            SysExpressionWhere_Analyize(exp.Body, builder);
            return builder.ToString();
        }

        private static SysLE.Expression SysExpressionWhere_Analyize(SysLE.Expression exp, StringBuilder builder)
        {
            if (exp == null) return null;

            SysLE.BinaryExpression binEx = exp as SysLE.BinaryExpression;
            if (binEx != null) SysExpressionWhere_Analyize(binEx.Left, builder);

            switch (exp.NodeType)
            {
                case SysLE.ExpressionType.Parameter:
                    {
                        SysLE.ParameterExpression param = (SysLE.ParameterExpression)exp;
                        builder.Append("(" + param.Name);
                        return null;
                    }
                case SysLE.ExpressionType.MemberAccess:
                    {
                        SysLE.MemberExpression mexp = (SysLE.MemberExpression)exp;
                        builder.Append("(" + mexp.Member.Name);
                        return null;
                    }
                case SysLE.ExpressionType.Constant:
                    {
                        SysLE.ConstantExpression cex = (SysLE.ConstantExpression)exp;
                        if (cex.Value is string) builder.Append("'" + cex.Value.ToString() + "') ");
                        else builder.Append(cex.Value.ToString() + ")");
                        return null;
                    }
                default:
                    {
                        if (exp.NodeType == SysLE.ExpressionType.Equal) builder.Append("=");
                        else if (exp.NodeType == SysLE.ExpressionType.NotEqual) builder.Append("<>");
                        else if (exp.NodeType == SysLE.ExpressionType.LessThan) builder.Append("<");
                        else if (exp.NodeType == SysLE.ExpressionType.LessThanOrEqual) builder.Append("<=");
                        else if (exp.NodeType == SysLE.ExpressionType.GreaterThan) builder.Append(">");
                        else if (exp.NodeType == SysLE.ExpressionType.GreaterThanOrEqual) builder.Append(">=");
                        else if (exp.NodeType == SysLE.ExpressionType.AndAlso || exp.NodeType == SysLE.ExpressionType.And)
                        {
                            builder.Append("and");
                        }
                        else if (exp.NodeType == SysLE.ExpressionType.OrElse || exp.NodeType == SysLE.ExpressionType.Or)
                        {
                            builder.Append("or");
                        }
                    }
                    break;
            }

            if (binEx != null) SysExpressionWhere_Analyize(binEx.Right, builder);

            return binEx;
        }

        #endregion

        #region  In
        public static In In(this Where where, params string[] values)
        {
            In _in = new In(values);
            _in.SqlString = where.SqlString + _in.ToString();

            return _in;
        }

        #endregion

        #region exists

        public static Exists Exists(this Where where, string values)
        {
            Exists _exists = new Exists(values);
            _exists.SqlString = where.SqlString + _exists.ToString();

            return _exists;
        }

        #endregion

        #region notexists

        public static NotExists NotExists(this Where where, string values)
        {
            NotExists _notEists = new NotExists(values);
            _notEists.SqlString = where.SqlString + _notEists.ToString();

            return _notEists;
        }

        #endregion

        #region group by 关键字拼接
        public static GroupBy GroupBy(this From from, params string[] groupNames)
        {
            GroupBy groupby = new GroupBy(groupNames);
            groupby.SqlString = from.SqlString + groupby.ToString();

            return groupby;
        }
        #endregion

        #region order by 关键字拼接
        /// <summary>
        /// 默认Asc(升序)
        /// </summary>
        /// <param name="from"></param>
        /// <param name="Names"></param>
        /// <returns></returns>
        public static OrderBy OrderBy(this From from, params string[] Names)
        {
            OrderBy orderby = new OrderBy(Names);
            orderby.SqlString = from.SqlString + orderby.ToString();

            return orderby;
        }

        public static OrderBy OrderBy(this From from, Ordering[] orderings, params string[] Names)
        {
            OrderBy orderby = new OrderBy(Names);
            orderby.SqlString = from.SqlString + orderby.ToString(orderings);

            return orderby;
        }

        public static OrderBy OrderBy<T, TSource>(this From from, SysLE.Expression<Func<T, TSource>> exp)
        {
            OrderBy orderby = new OrderBy(SysExpression_Analyize<T, TSource>(exp));
            orderby.SqlString = from.SqlString + orderby.ToString();

            return orderby;
        }

        private static string SysExpression_Analyize<T, TSource>(SysLE.Expression<Func<T, TSource>> exp)
        {
            if (exp.Body.NodeType == SysLE.ExpressionType.Parameter) return exp.Name;
            else if (exp.Body.NodeType == SysLE.ExpressionType.MemberAccess)
            {
                SysLE.MemberExpression mexp = (SysLE.MemberExpression)exp.Body;
                if (mexp == null) return string.Empty;
                else return mexp.Member.Name;
            }
            else return string.Empty;
        }

        #endregion

        //update
        public static Set Set(this Update update,string tableName,params KeyValue[] kvalue)
        {
            Set set = new Set(kvalue);
            set.SqlString = update.SqlString + set.ToString();

            return set;
        } 

        public static Set<T> Set<T>(this Update<T> update,T Entity)
        {
            Set<T> set = new Expression.Set<T>(Entity);
            set.SqlString = update.SqlString + set.ToString();
           
            return set;
        }
    }
}
